#include "process.h"
#include "disk.h"
#include "observer.h"

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* By Jacob Eichers and Cliff Buchanan. Contains the functions used by the
	process structure.*/

/* print statistics about a specific process*/
void proc_print(struct process *proc)
{
	printf("%d: %s, %d/%d\" %d/%d blocks\n",
		proc->arrivalTime, proc->name, proc->time, proc->lifeTime,
		proc->ioOps, proc->lifeIOOps);
}

/* Allocate memory for and create a new process.*/
struct process *proc_create(char *name, int arrivalTime, int time, int io)
{
	struct process *p;
	
	p = malloc(sizeof(struct process));
	if(!p)
	{
		fprintf(stderr, "proc_create: malloc failed!\n");
		exit(-1);
	}
	p->name = calloc(sizeof(char), strlen(name)+1);
	if(!p->name)
	{
		fprintf(stderr, "proc_create: malloc failed!\n");
		exit(-1);
	}

	p->arrivalTime = arrivalTime;
	strcpy(p->name, name);
	p->lifeTime = time;
	p->lifeIO = io;
	p->lifeIOOps = (io+DISK_BLOCK_SIZE-1)/DISK_BLOCK_SIZE;
	p->time = 0;
	p->ioOps = 0;
	p->priority = 0;
	p->lastRun = 0;

	return p;
}

/*Inform a process of how long it just ran.*/
void proc_ran(struct process *proc, int time)
{
	proc->time += time;
	proc->lastRun = time;

	obs_proc_ran(proc, time);
}

/* Inform a process it did IO*/
void proc_did_io(struct process *proc, int blocks)
{
	proc->ioOps++;

	obs_proc_did_io(proc, blocks);
}

/* Adjust process priority*/
void proc_set_priority(struct process *proc, int priority)
{
	proc->priority = priority;
}

/* Destruct and log exit of a process*/
void proc_exit(struct process *proc)
{
	obs_proc_exit(proc);

	free(proc->name);
	free(proc);
}

/* Returns 0 iff process still has incomplete IO OR CPU time*/
int proc_done(struct process *proc)
{
	return (proc->time)>=(proc->lifeTime) &&
		(proc->ioOps)>=(proc->lifeIOOps);
}

/* Returns the amount of CPU time a process wants to run before
	either exiting or performing IO.*/
int proc_time_to_event(struct process *proc)
{
	int q, timeLeft, ioOpsLeft;

	/* calculate the time quantum between IO bursts*/
	q = proc->lifeTime/(!proc->lifeIOOps ? 1 : proc->lifeIOOps);
	if( q<=0 )
		{q=1;}
	timeLeft = (proc->lifeTime)-(proc->time);
	ioOpsLeft = (proc->lifeIOOps)-(proc->ioOps);
	
	/* if CPU time is done*/
	if( timeLeft<=0 )
		{return 0;}
	/* if all IO is done*/
	else if( ioOpsLeft<=0 )
		{return timeLeft;}
	else
		{return q*((proc->ioOps)+1)-proc->time;}
}

